#include "Python.h"
#include <wiringPi.h>

static unsigned char ds18b20_reset(int DQ) {
    unsigned char ack;
    pinMode(DQ,OUTPUT);
    digitalWrite(DQ,1);
    delayMicroseconds(1000);
    digitalWrite(DQ,0);//将总线拉低480us-960us ，总线上所有器件都将被复位
    delayMicroseconds(495);//保持低电平，使得MASTER Tx > 480us
    digitalWrite(DQ,1);//拉高电平，释放总线，如果DS18B20做出反应将在15us~60us后拉低总线
    delayMicroseconds(80);//等待DS18B20拉低总线
    pinMode(DQ,INPUT);
    ack = digitalRead(DQ);//获取总线状态
    pinMode(DQ,OUTPUT);
    delayMicroseconds(380);//调节MASTER TR > 480us
    return ack;//成功返回0，失败返回1
}

static void ds18b20_write_byte(int DQ,unsigned char val) {
    unsigned char i,bit;
    for(i=0;i<8;i++){//写入一个字节的数据，一个时序中写一次
        bit=(val>>i)&0x01;
        if(bit){
            digitalWrite(DQ,0);//拉低总线
            delayMicroseconds(1);//延时>1us
            digitalWrite(DQ,1);//主机输出高电平
            delayMicroseconds(80);//60us < Tx “1”
        }else{
            digitalWrite(DQ,0);//主机拉低总线
            delayMicroseconds(80);//60us < Tx “0” < 120us
            digitalWrite(DQ,1);//主机释放总线，恢复高电平
            delayMicroseconds(1);//TREC > 1us
        };
    };
}

static unsigned char ds18b20_read_byte(int DQ) {
    unsigned char i,bit,value=0;
    for(i=0;i<8;i++){
        digitalWrite(DQ,0);//拉低总线，开始读时序
        delayMicroseconds(1);//读数据之前先把总线拉低>1us
        digitalWrite(DQ,1);//释放总线
        delayMicroseconds(11);//延时到采样位置
        pinMode(DQ,INPUT);
        bit=digitalRead(DQ);//获取总线值
        pinMode(DQ,OUTPUT);
        delayMicroseconds(48);//延时以完成此次读时序60us
        value|=(bit&0x01)<<i;//读一字节数据，一个时序中读一次，并作移位处理
    };
    return value;
}

static char ds18b20_read_temp(int DQ,float* temperature) {
    char ack;
    unsigned char msb,lsb;
    if(temperature==NULL){
        return -1;
    };
    ack=ds18b20_reset(DQ);//复位
    //18B20内部温度转换
    ds18b20_write_byte(DQ,0xCC);//仅一个DS18b20，跳过ROM
    ds18b20_write_byte(DQ,0x44);//温度转换
    delay(700);//延时>600ms
    ds18b20_reset(DQ);//复位，每一次读写之前都要对DS18B20进行复位操作
    ds18b20_write_byte(DQ,0xCC);//仅一个DS18b20，跳过ROM
    ds18b20_write_byte(DQ,0xBE);//读温度数据
    lsb=ds18b20_read_byte(DQ);//读LSB
    msb=ds18b20_read_byte(DQ);//读MSB
    *temperature=(float)((msb<<8)|lsb)/16;
    return ack;
}

static PyObject* pyfunc_ds18b20_read(PyObject* self,PyObject* args){
    int pin;
    char ack;
    float temperature;
    if(!PyArg_ParseTuple(args,"i",&pin)) {
        return NULL;
    };
    wiringPiSetupPhys();
    ack=ds18b20_read_temp(pin,&temperature);
    return Py_BuildValue("if",ack,temperature);
}

static PyMethodDef module_methods[]={
    {"read",pyfunc_ds18b20_read,METH_VARARGS,NULL},
    {NULL,NULL,0,NULL}
};

#if PY_MAJOR_VERSION > 2
static struct PyModuleDef ds18b20_module={
    PyModuleDef_HEAD_INIT,
    "ds18b20",
    NULL,
    -1,
    module_methods
};
#endif

#if PY_MAJOR_VERSION > 2
PyMODINIT_FUNC PyInit_ds18b20(void)
#else
PyMODINIT_FUNC initds18b20(void)
#endif
{
    #if PY_MAJOR_VERSION > 2
        PyObject* module=PyModule_Create(&ds18b20_module);
        return module;
    #else
        Py_InitModule("ds18b20",module_methods);
        return;
    #endif
}